package mmpathgen.core;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import mmpathgen.callgraphanalysis.CallGraphAnalysis;
import mmpathgen.callgraphanalysis.CallGraphGenByCHA;
import mmpathgen.callgraphanalysis.CallGraphGenBySpark;
import mmpathgen.callgraphanalysis.FilteredCallGraph;
import mmpathgen.util.JRELibFilter;
import soot.SootMethod;
import soot.jimple.toolkits.annotation.purity.SootMethodFilter;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.options.Options;

public class CopyOfMMPathGen_20100623_BeforePathRefining {

	static {
		soot.options.Options.v().set_keep_line_number(true);
	}

	/**
	 * @param args
	 * @throws FileNotFoundException 
	 */
	public static void main(String[] args) throws FileNotFoundException {

		// get the class names automatically
		File path = new File("D:\\workspace\\MMPath\\sutdriver");

		// set main application class
		String mainClassName = "siena.Compare";
		
		// package name
		String srcFolder = "";

		mmpathGen_CHA_Filtered_Brief(path, srcFolder, mainClassName);	
		mmpathGen_Spark_Filtered_Brief(path, srcFolder, mainClassName);

//		System.out.println("total potential MM-Path: " + fcg.getTails().size());

	}
	

	/**
	 * @param path
	 * @param mainClassName
	 * @throws FileNotFoundException
	 */
	private static void mmpathGen_CHA_Filtered_Brief(File path,
			String srcFolder, String mainClassName) throws FileNotFoundException {

		String cgaType = "CHA";
		String filtType = "Filted";
		String cfaType = "Brief";
		
		Options.v().set_output_dir("sootOutput." + srcFolder + "." + mainClassName + "." + cgaType + "_" + filtType + "_" + cfaType);

		// redirecting the standard output
		PrintStream console = System.out;
		PrintStream redirectedOut = new PrintStream(new BufferedOutputStream(
				new FileOutputStream(mainClassName + "_CHA_Filtered_Brief.txt")),
				true);
		System.setOut(redirectedOut);

		// construct call graph

		long startTime = System.currentTimeMillis();

		CallGraph cg = CallGraphGenByCHA.cgGen(path, mainClassName);

		SootMethodFilter filter = new JRELibFilter();

		FilteredCallGraph fcg = CallGraphAnalysis.getFilteredCallGraph(cg, filter);

		CallGraphAnalysis.printCallGraphAsDot(fcg, mainClassName, cgaType,
				filtType, cfaType);

		// generate MM-Paths
		genMMPath(fcg);

		// reset static path containers
		mmPath = new LinkedList<SootMethod>();
		allPaths = new HashSet<LinkedList<SootMethod>>();
		
		long finishTime = System.currentTimeMillis();

		long costTime = finishTime - startTime;

		long costTimeInSec = costTime / 1000;

		System.out.println("costTimeInSec: " + costTimeInSec);

		// close the standard output redirection
		redirectedOut.close();
		System.setOut(console);
	}

	/**
	 * @param path
	 * @param mainClassName
	 * @throws FileNotFoundException
	 */
	private static void mmpathGen_Spark_Filtered_Brief(File path, String srcFolder,
			String mainClassName) throws FileNotFoundException {

		String cgaType = "Spark";
		String filtType = "Filted";
		String cfaType = "Brief";
		
		Options.v().set_output_dir("sootOutput." + srcFolder + "." + mainClassName + "." + cgaType + "_" + filtType + "_" + cfaType);

		// redirecting the standard output
		PrintStream console = System.out;
		PrintStream redirectedOut = new PrintStream(
				new BufferedOutputStream(new FileOutputStream(mainClassName
						+ "_Spark_Filtered_Brief.txt")), true);
		System.setOut(redirectedOut);

		// construct call graph

		long startTime = System.currentTimeMillis();

		CallGraph cg = CallGraphGenBySpark.cgGen(path, mainClassName);

		SootMethodFilter filter = new JRELibFilter();

		FilteredCallGraph fcg = CallGraphAnalysis.getFilteredCallGraph(cg, filter);

		CallGraphAnalysis.printCallGraphAsDot(fcg, mainClassName, cgaType,
				filtType, cfaType);

		// generate MM-Paths
		genMMPath(fcg);
		
		// reset static path containers
		mmPath = new LinkedList<SootMethod>();
		allPaths = new HashSet<LinkedList<SootMethod>>();

		long finishTime = System.currentTimeMillis();

		long costTime = finishTime - startTime;

		long costTimeInSec = costTime / 1000;

		System.out.println("costTimeInSec: " + costTimeInSec);

		// close the standard output redirection
		redirectedOut.close();
		System.setOut(console);
	}
	
	static LinkedList<SootMethod> mmPath = new LinkedList<SootMethod>();
	static Set<LinkedList<SootMethod>> allPaths = new HashSet<LinkedList<SootMethod>>();
	
	public void findPath(FilteredCallGraph fcg, SootMethod current,
			SootMethod target, LinkedList<SootMethod> path) {

		if (current.equals(target)) {
			path.add(current);
			mmPath.addAll(path);
			allPaths.add(new LinkedList<SootMethod>(mmPath));
//			mmPath.clear();
			return;
		}

		// to avoid infinite recursion
		if (path.contains(current)) {
			return;
		}

		path.add(current);

		for (SootMethod child : fcg.getSuccsOf(current)) {
			findPath(fcg, child, target, path);
		}
		path.removeLast(); // to avoid add the target node twice
	}

	public void vacationPaths(FilteredCallGraph fcg, SootMethod start) {

		List<SootMethod> leaves = fcg.getTails();

		for (SootMethod leaf : leaves) {
			if (!leaf.equals(start)) {
				findPath(fcg, start, leaf, new LinkedList<SootMethod>());
			}
		}
	}

	public static void genMMPath(FilteredCallGraph fcg) {

//		System.out.println("genMMPath");
		List<SootMethod> heads = fcg.getHeads();
		CopyOfMMPathGen_20100623_BeforePathRefining gen = new CopyOfMMPathGen_20100623_BeforePathRefining();
		for (SootMethod head : heads) {
			gen.vacationPaths(fcg, head);

			for (LinkedList<SootMethod> mmPath : allPaths) {
				System.out.print(mmPath.poll());
				for (SootMethod mtd : mmPath) {
					System.out.print("->" + mtd);
				}
				System.out.println();
			}

		}
	}
	

}

